﻿// Decompiled with JetBrains decompiler
// Type: Microsoft.InfoCards.SelfIssuedSamlTokenFactory
// Assembly: infocard, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 8E14765A-6610-409A-BA36-099A0642905D
// Assembly location: E:\git\ALLIDA\windll\infocard.exe

using Microsoft.InfoCards.Diagnostics;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IdentityModel.Tokens;
using System.IO;
using System.Security.Cryptography;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.Xml;

namespace Microsoft.InfoCards
{
  internal class SelfIssuedSamlTokenFactory : TokenFactoryBase
  {
    public static readonly TimeSpan TokenLifetime = new TimeSpan(1, 0, 0);
    private static readonly SamlSerializer samlSerializer = new SamlSerializer();
    private string m_signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
    private string m_encryptionAlgorithm = SecurityAlgorithmSuite.Default.DefaultEncryptionAlgorithm;
    private const string SamlAssertionIdPrefix = "SamlSecurityToken-";
    private const string DefaultDigestAlgorithm = "http://www.w3.org/2000/09/xmldsig#sha1";
    private string m_encryptWithAlgorithm;
    private string m_keyWrapAlgorithm;

    protected override TokenDescriptor ProduceToken(
      InfoCard card,
      TokenCreationParameter creationParam,
      TokenFactoryCredential credential,
      InfoCardPolicy policy,
      bool discloseOptional)
    {
      RSACryptoServiceProvider cryptoServiceProvider = (RSACryptoServiceProvider) null;
      SymmetricAlgorithm symmetricProof = (SymmetricAlgorithm) null;
      if (!string.IsNullOrEmpty(policy.OptionalRstParams.SignatureAlgorithm))
        this.m_signatureAlgorithm = policy.OptionalRstParams.SignatureAlgorithm;
      if (!string.IsNullOrEmpty(policy.OptionalRstParams.EncryptionAlgorithm))
        this.m_encryptionAlgorithm = policy.OptionalRstParams.EncryptionAlgorithm;
      TokenDescriptor tokenDescriptor;
      try
      {
        List<InfoCardClaim> claimSet = this.GetClaimSet(card, policy, discloseOptional);
        List<string> stringList = new List<string>(claimSet.Count);
        for (int index = 0; index < claimSet.Count; ++index)
          stringList.Add(claimSet[index].Id);
        SamlSecurityToken samlToken;
        DisplayToken displayToken;
        XmlElement protectedToken;
        using (RSACryptoServiceProvider publicCryptography = card.GetPublicCryptography(policy.Recipient.GetIdentifier()))
        {
          SecurityKeyIdentifier issuerKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[1]
          {
            (SecurityKeyIdentifierClause) new RsaKeyIdentifierClause((RSA) publicCryptography)
          });
          SecurityKeyIdentifier proofKeyIdentifier;
          SecurityKey proofCryptoInsideSamlToken;
          if (policy.KeyType == SecurityKeyTypeInternal.SymmetricKey)
          {
            InfoCardTrace.Assert(policy.ImmediateTokenRecipient is X509RecipientIdentity, "Symmetric key type is not allowed when no certifcate is provided for the token recipeint");
            this.m_keyWrapAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm;
            InfoCardTrace.Assert("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" == this.m_keyWrapAlgorithm, "What we have chosen");
            this.m_encryptWithAlgorithm = string.IsNullOrEmpty(policy.OptionalRstParams.EncryptWith) ? SecurityAlgorithmSuite.Default.DefaultEncryptionAlgorithm : policy.OptionalRstParams.EncryptWith;
            symmetricProof = (SymmetricAlgorithm) new RijndaelManaged();
            SecurityAlgorithmSuite securityAlgorithmSuite;
            switch (this.m_encryptWithAlgorithm)
            {
              case "http://www.w3.org/2001/04/xmlenc#aes128-cbc":
                securityAlgorithmSuite = SecurityAlgorithmSuite.Basic128;
                break;
              case "http://www.w3.org/2001/04/xmlenc#aes192-cbc":
                securityAlgorithmSuite = SecurityAlgorithmSuite.Basic192;
                break;
              case "http://www.w3.org/2001/04/xmlenc#aes256-cbc":
                securityAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
                break;
              case "http://www.w3.org/2001/04/xmlenc#tripledes-cbc":
                securityAlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
                break;
              default:
                throw InfoCardTrace.ThrowHelperError((Exception) new TokenCreationException(SR.GetString("UnsupportedEncryptWithAlgorithm", (object) this.m_encryptWithAlgorithm)));
            }
            symmetricProof.KeySize = securityAlgorithmSuite.DefaultSymmetricKeyLength;
            X509SecurityToken x509SecurityToken = new X509SecurityToken(((X509RecipientIdentity) policy.ImmediateTokenRecipient).LeafCertificate, Guid.NewGuid().ToString());
            SecurityKeyIdentifier encryptingKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[1]
            {
              (SecurityKeyIdentifierClause) x509SecurityToken.CreateKeyIdentifierClause<X509ThumbprintKeyIdentifierClause>()
            });
            proofKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[1]
            {
              (SecurityKeyIdentifierClause) new EncryptedKeyIdentifierClause(x509SecurityToken.SecurityKeys[0].EncryptKey(this.m_keyWrapAlgorithm, symmetricProof.Key), this.m_keyWrapAlgorithm, encryptingKeyIdentifier)
            });
            proofCryptoInsideSamlToken = (SecurityKey) new InMemorySymmetricSecurityKey(symmetricProof.Key);
            this.ThrowIfProofKeyOperationsNotSupported(policy, proofCryptoInsideSamlToken);
          }
          else if (SecurityKeyTypeInternal.AsymmetricKey == policy.KeyType)
          {
            this.m_encryptWithAlgorithm = string.IsNullOrEmpty(policy.OptionalRstParams.EncryptWith) ? SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm : policy.OptionalRstParams.EncryptWith;
            this.m_keyWrapAlgorithm = this.m_encryptWithAlgorithm;
            symmetricProof = (SymmetricAlgorithm) null;
            cryptoServiceProvider = publicCryptography;
            proofKeyIdentifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[1]
            {
              (SecurityKeyIdentifierClause) new RsaKeyIdentifierClause((RSA) cryptoServiceProvider)
            });
            proofCryptoInsideSamlToken = proofKeyIdentifier.CreateKey();
            this.ThrowIfProofKeyOperationsNotSupported(policy, proofCryptoInsideSamlToken);
          }
          else
          {
            this.m_keyWrapAlgorithm = SecurityAlgorithmSuite.Default.DefaultAsymmetricKeyWrapAlgorithm;
            InfoCardTrace.Assert("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" == this.m_keyWrapAlgorithm, "What we have chosen");
            InfoCardTrace.Assert(SecurityKeyTypeInternal.NoKey == policy.KeyType, "Bad enum member for SecurityKeyTypeInternal.");
            proofKeyIdentifier = (SecurityKeyIdentifier) null;
            proofCryptoInsideSamlToken = (SecurityKey) null;
          }
          using (SelfIssuedAuthAsymmetricKey authAsymmetricKey = new SelfIssuedAuthAsymmetricKey(card.GetPrivateCryptography(policy.Recipient.GetIdentifier())))
          {
            Uri uri = policy.ImmediateTokenRecipient.Address.Uri;
            if ((EndpointAddress) null != policy.PolicyAppliesTo)
              uri = policy.PolicyAppliesTo.Uri;
            samlToken = this.CreateSamlToken(claimSet, issuerKeyIdentifier, proofKeyIdentifier, proofCryptoInsideSamlToken, (SecurityKey) authAsymmetricKey, uri);
            displayToken = this.CreateDisplayToken(claimSet);
            X509RecipientIdentity immediateTokenRecipient = policy.ImmediateTokenRecipient as X509RecipientIdentity;
            if (immediateTokenRecipient != null)
            {
              protectedToken = EncryptionUtility.EncryptSecurityToken((SecurityToken) samlToken, immediateTokenRecipient.LeafCertificate, this.m_encryptionAlgorithm, this.m_keyWrapAlgorithm, policy.ProtocolVersionProfile);
            }
            else
            {
              MemoryStream memoryStream = new MemoryStream();
              XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter((XmlWriter) new XmlTextWriter((TextWriter) new StreamWriter((Stream) memoryStream)));
              policy.ProtocolVersionProfile.TokenSerializer.WriteToken((XmlWriter) dictionaryWriter, (SecurityToken) samlToken);
              dictionaryWriter.Flush();
              memoryStream.Seek(0L, SeekOrigin.Begin);
              protectedToken = (XmlElement) new XmlDocument().ReadNode((XmlReader) Utility.CreateReaderWithQuotas((Stream) memoryStream));
              Array.Clear((Array) memoryStream.GetBuffer(), 0, Convert.ToInt32(memoryStream.Length));
              memoryStream.Close();
            }
          }
        }
        StringWriter stringWriter = new StringWriter((IFormatProvider) CultureInfo.InvariantCulture);
        policy.ProtocolVersionProfile.TokenSerializer.WriteKeyIdentifierClause((XmlWriter) XmlDictionaryWriter.CreateDictionaryWriter((XmlWriter) new XmlTextWriter((TextWriter) stringWriter)), (SecurityKeyIdentifierClause) new SamlAssertionKeyIdentifierClause(samlToken.Id));
        stringWriter.Flush();
        string str = stringWriter.GetStringBuilder().ToString();
        tokenDescriptor = new TokenDescriptor(samlToken.Id, samlToken.ValidFrom, samlToken.ValidTo, protectedToken, displayToken, symmetricProof, str, str, (IEnumerable<string>) stringList);
        symmetricProof = (SymmetricAlgorithm) null;
      }
      catch (InfoCardBaseException ex)
      {
        throw;
      }
      catch (Exception ex)
      {
        if (!InfoCardTrace.IsFatal(ex))
          throw InfoCardTrace.ThrowHelperError((Exception) new TokenCreationException((string) null, ex));
        throw;
      }
      finally
      {
        ((IDisposable) cryptoServiceProvider)?.Dispose();
        ((IDisposable) symmetricProof)?.Dispose();
      }
      return tokenDescriptor;
    }

    private void ThrowIfProofKeyOperationsNotSupported(
      InfoCardPolicy policy,
      SecurityKey proofCryptoInsideSamlToken)
    {
      if (!string.IsNullOrEmpty(policy.OptionalRstParams.SignWith) && !proofCryptoInsideSamlToken.IsSupportedAlgorithm(policy.OptionalRstParams.SignWith))
        throw InfoCardTrace.ThrowHelperError((Exception) new TokenCreationException(SR.GetString("UnsupportedSignWithAlgorithm", (object) policy.OptionalRstParams.SignWith)));
      if (!proofCryptoInsideSamlToken.IsSupportedAlgorithm(this.m_encryptWithAlgorithm))
        throw InfoCardTrace.ThrowHelperError((Exception) new TokenCreationException(SR.GetString("UnsupportedEncryptWithAlgorithm", (object) this.m_encryptWithAlgorithm)));
    }

    private SamlSecurityToken CreateSamlToken(
      List<InfoCardClaim> claims,
      SecurityKeyIdentifier issuerKeyIdentifier,
      SecurityKeyIdentifier proofKeyIdentifier,
      SecurityKey proofCryptoInsideSamlToken,
      SecurityKey issuerSigningKey,
      Uri immediateTokenRecipientUri)
    {
      DateTime utcNow = DateTime.UtcNow;
      SamlAudienceRestrictionCondition restrictionCondition = new SamlAudienceRestrictionCondition((IEnumerable<Uri>) new Collection<Uri>()
      {
        immediateTokenRecipientUri
      });
      SamlConditions samlConditions = new SamlConditions(utcNow, utcNow.Add(SelfIssuedSamlTokenFactory.TokenLifetime), (IEnumerable<SamlCondition>) new Collection<SamlCondition>()
      {
        (SamlCondition) restrictionCondition
      });
      SamlSubject samlSubject = new SamlSubject((string) null, (string) null, (string) null, (IEnumerable<string>) new string[1]
      {
        proofKeyIdentifier != null ? SamlConstants.HolderOfKey : "urn:oasis:names:tc:SAML:1.0:cm:bearer"
      }, (string) null, proofKeyIdentifier);
      if (proofCryptoInsideSamlToken != null)
        samlSubject.Crypto = proofCryptoInsideSamlToken;
      List<SamlAttribute> samlAttributeList = new List<SamlAttribute>(claims.Count);
      char[] chArray = new char[1]{ '/' };
      for (int index = 0; index < claims.Count; ++index)
      {
        string[] strArray = claims[index].Id.Split(chArray);
        InfoCardTrace.ThrowInvalidArgumentConditional(0 == strArray.Length, "claimUri");
        string attributeName = strArray[strArray.Length - 1];
        if (claims[index].Id == InfoCardConstants.Gender)
          InfoCardTrace.Assert(claims[index].Value == "0" || claims[index].Value == "1" || claims[index].Value == "2", "Wrong value type for gender claim, only values '0' (Unspecified), '1' (Male) and '2' (Female) are allowed ");
        if (claims[index].Id == InfoCardConstants.DateOfBirth)
        {
          DateTime universalTime = DateTime.Parse(claims[index].Value, (IFormatProvider) CultureInfo.InvariantCulture).ToUniversalTime();
          InfoCardTrace.Assert(true, "Invalid value for date of birth ");
          samlAttributeList.Add(new SamlAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims", attributeName, (IEnumerable<string>) new string[1]
          {
            XmlConvert.ToString(universalTime, XmlDateTimeSerializationMode.Utc)
          }));
        }
        else
          samlAttributeList.Add(new SamlAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims", attributeName, (IEnumerable<string>) new string[1]
          {
            claims[index].ToString()
          }));
      }
      SamlAttributeStatement attributeStatement = new SamlAttributeStatement(samlSubject, (IEnumerable<SamlAttribute>) samlAttributeList);
      SamlAssertion assertion = new SamlAssertion("SamlSecurityToken-" + Guid.NewGuid().ToString(), "http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self", utcNow, samlConditions, (SamlAdvice) null, (IEnumerable<SamlStatement>) new List<SamlStatement>(1)
      {
        (SamlStatement) attributeStatement
      });
      if (!issuerSigningKey.IsSupportedAlgorithm(this.m_signatureAlgorithm))
        throw InfoCardTrace.ThrowHelperError((Exception) new TokenCreationException(SR.GetString("UnsupportedSignatureAlgorithm", (object) this.m_signatureAlgorithm)));
      assertion.SigningCredentials = new SigningCredentials(issuerSigningKey, this.m_signatureAlgorithm, "http://www.w3.org/2000/09/xmldsig#sha1", issuerKeyIdentifier);
      return new SamlSecurityToken(assertion);
    }

    private DisplayToken CreateDisplayToken(List<InfoCardClaim> claims)
    {
      List<DisplayClaim> claimList = new List<DisplayClaim>();
      for (int index = 0; index < claims.Count; ++index)
      {
        DisplayClaim displayClaim = new DisplayClaim(InfoCardConstants.ClaimDisplayTag(claims[index].Id.ToString()), new List<string>()
        {
          claims[index].Value
        }, InfoCardConstants.ClaimsDescription(claims[index].Id.ToString()), claims[index].Id.ToString());
        claimList.Add(displayClaim);
      }
      return new DisplayToken(claimList);
    }

    private List<InfoCardClaim> GetClaimSet(
      InfoCard card,
      InfoCardPolicy policy,
      bool discloseOptional)
    {
      StoreConnection connection = StoreConnection.GetConnection();
      try
      {
        List<InfoCardClaim> intersectedClaims = (List<InfoCardClaim>) null;
        if (policy.RequiredClaims != null)
        {
          intersectedClaims = new List<InfoCardClaim>(policy.RequiredClaims.Length);
          this.AddClaimsThatIntersect(policy.RequiredClaims, false, card.GetClaims(), policy.ImmediateTokenRecipient.GetOrganizationPPIDIdentifier(), card.Id, intersectedClaims);
        }
        if (discloseOptional && policy.OptionalClaims != null)
        {
          if (intersectedClaims == null)
            intersectedClaims = new List<InfoCardClaim>(policy.OptionalClaims.Length);
          this.AddClaimsThatIntersect(policy.OptionalClaims, true, card.GetClaims(), policy.ImmediateTokenRecipient.GetOrganizationPPIDIdentifier(), card.Id, intersectedClaims);
        }
        return intersectedClaims;
      }
      finally
      {
        connection.Close();
      }
    }

    private void AddClaimsThatIntersect(
      string[] policyClaims,
      bool processingOptionalClaims,
      InfoCardClaimCollection claims,
      string recipientidentifier,
      Uri cardId,
      List<InfoCardClaim> intersectedClaims)
    {
      foreach (string policyClaim in policyClaims)
      {
        if (policyClaim == InfoCardConstants.PPIDClaimsUri)
        {
          string ppid = Utility.CreatePpid(Convert.FromBase64String(recipientidentifier), cardId);
          intersectedClaims.Add(new InfoCardClaim(InfoCardConstants.PPIDClaimsUri, ppid));
        }
        else if (!processingOptionalClaims)
        {
          InfoCardTrace.ThrowInvalidArgumentConditional(!claims.ContainsKey(policyClaim) || claims[policyClaim] == null || string.IsNullOrEmpty(claims[policyClaim].Value), "policyClaimUri");
          intersectedClaims.Add(claims[policyClaim]);
        }
        else
        {
          InfoCardClaim infoCardClaim = (InfoCardClaim) null;
          if (claims.ContainsKey(policyClaim))
            infoCardClaim = claims[policyClaim];
          if (infoCardClaim != null && !string.IsNullOrEmpty(infoCardClaim.Value))
            intersectedClaims.Add(infoCardClaim);
        }
      }
    }
  }
}
